﻿

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using Newtonsoft.Json;

namespace CanVasLib.Diagram
{
	/// <summary>
	/// 连接点.
	/// </summary>
	public class Connector : Entity
	{
        #region Constructor
        /// <summary>
        /// Default connector
        /// </summary>
        public Connector()
        {
            attachedConnectors = new List<Connector>();
        }

        /// <summary>
        /// Constructs a connector, passing its location
        /// </summary>
        /// <param name="p"></param>
        public Connector(DiagramPoint p)
        {
            attachedConnectors = new List<Connector>();
            Point = p;
        }

        #endregion

        #region Events

		public event EventHandler<LocationEventArgs> LocationChanged;
		private void OnLocationChanged(LocationEventArgs e)
		{
			LocationChanged?.Invoke(this, e);
		}
		public event EventHandler<AttachedToChangedEventArgs> AttachedToChanged;
		private void OnAttachedToChanged(AttachedToChangedEventArgs e)
		{
			AttachedToChanged?.Invoke(this, e);
		}

		#endregion

		#region Fields
		/// <summary>
		/// 此连接器的位置
		/// </summary>
		protected DiagramPoint point;
		/// <summary>
		/// 以我为目标的连接点，可能有多个
		/// </summary>
		protected List<Connector> attachedConnectors;
		/// <summary>
		/// 以我为出发点的连接点,只有一个
		/// </summary>
		protected Connector attachedTo;
		/// <summary>
		/// the name of this connector
		/// </summary>
		protected string name;

        private ConnectorDirection? _connectorDirection = null;
        private string _ownerId;

        #endregion

		#region Properties
		//我的主人,可能是Tool或Connection
		[JsonIgnore]
        public Entity OwnerEntity { get; set; }

		//在Tool里的索引,0,1,2,3,上下左右
		public int ConnectorsIndexOfContainEntity { get; set; } = -1;

        [Browsable(false)]
        public string OwnerID
        {
            get => _ownerId;
            set { _ownerId = value; }
        }

        /// <summary>
		/// The name of this connector
		/// </summary>
		public string Name
		{
			get { return name; }
			set { name = value; }
		}

        [Browsable(false)]
		public int Index { get; set; } = 0;

        public ConnectorDirection ConnectorDirection
		{
			get
			{
				if (_connectorDirection != null && point != null)
					point.ConnectorDirection = (ConnectorDirection)_connectorDirection;

				if (point == null)
					return _connectorDirection ?? ConnectorDirection.Up;

				return point.ConnectorDirection;
			}
			set
			{
				if (point != null)
					point.ConnectorDirection = value;
				_connectorDirection = value;
			}
		}

		
		public Connector AttachedTo
		{
			get { return attachedTo; }
			set
			{
                if (attachedTo==null)
                {
                    return;
                }
				attachedTo = value;
				point = attachedTo.point.Copy();
				_connectorDirection = attachedTo.ConnectorDirection;
				OnAttachedToChanged(new AttachedToChangedEventArgs() { New = value });
			}
		}

		/// <summary>
		/// The location of this connector
		/// </summary>
		public DiagramPoint Point
		{
			get { return point; }
			set { point = value; if (_connectorDirection != null) point.ConnectorDirection = (ConnectorDirection)_connectorDirection; }
		}

		#endregion

        #region Methods
		/// <summary>
		/// Paints the connector on the canvas
		/// </summary>
		/// <param name="g"></param>
		public override void Paint(Graphics g)
		{
			if (Hovered && this.site != null)
				g.FillRectangle(Brushes.Cyan, point.X + this.site.ViewOriginPoint.GetPoint().X - 10, point.Y + this.site.ViewOriginPoint.GetPoint().Y - 10, 20, 20);
			//else
			//	g.FillRectangle(Brushes.Green, point.X + this.site.ViewOriginPoint.X - 2, point.Y + this.site.ViewOriginPoint.Y - 2, 4, 4);
		}

		/// <summary>
		/// Tests if the mouse hits this connector
		/// </summary>
		/// <param name="p"></param>
		/// <returns></returns>
		public override bool Hit(Point p)
		{
			p.X = p.X - this.site.ViewOriginPoint.GetPoint().X;
			p.Y = p.Y - this.site.ViewOriginPoint.GetPoint().Y;

			Point a = p;
			Point b = point.GetPoint();
			b.Offset(-7, -7);
			//a.Offset(-1,-1);
			Rectangle r = new Rectangle(a, new Size(0, 0));
			Rectangle d = new Rectangle(b, new Size(15, 15));
			return d.Contains(r);
		}

		/// <summary>
		/// Invalidates the connector
		/// </summary>
		public override void Invalidate()
		{
			Point p = point.GetPoint();
			p.X += this.site.ViewOriginPoint.GetPoint().X;
			p.Y += this.site.ViewOriginPoint.GetPoint().Y;
			p.Offset(-5, -5);
			site.Invalidate(new Rectangle(p, new Size(10, 10)));
		}

		/// <summary>
		/// Moves the connector with the given shift-vector
		/// </summary>
		/// <param name="p"></param>
		public override void Move(Point p)
		{
			OnLocationChanged(new LocationEventArgs() { OffsetX = p.X, OffsetY = p.Y });
			this.point.X = this.point.X + p.X;
			this.point.Y = this.point.Y + p.Y;
			for (int k = 0; k < attachedConnectors.Count; k++)
				attachedConnectors[k].Move(p);
		}

		/// <summary>
		/// 附加
		/// </summary>
		/// <param name="c"></param>
		public void AttachConnector(Connector c)
		{
			//remove from the previous, if any
			if (c.attachedTo != null)
			{
				c.attachedTo.attachedConnectors.Remove(c);
			}
			attachedConnectors.Add(c);
			c.AttachedTo = this;

		}

		/// <summary>
		/// 分离
		/// </summary>
		/// <param name="c"></param>
		public void DetachConnector(Connector c)
		{
			attachedConnectors.Remove(c);
		}

		/// <summary>
		/// Releases this connector from any other
		/// </summary>
		public void Release()
		{
			if (this.attachedTo != null)
			{
				this.attachedTo.attachedConnectors.Remove(this);
				this.AttachedTo = null;
			}

		}

		#endregion
	}


    public class LocationEventArgs : EventArgs
    {
        public int OffsetX = 0;
        public int OffsetY = 0;
    }
    public class AttachedToChangedEventArgs : EventArgs
    {
        public Connector New { get; set; }
    }
    public enum ConnectorDirection
    {
        Left,
        Down,
        Right,
        Up
}
}
